﻿using Consul;
using Microsoft.Extensions.Options;

namespace Qzb.MicroService.Common.ConsulExtensions.Client
{
    public abstract class ConsulDispatcher
    {
        protected readonly ConsulOptions _options;

        public ConsulDispatcher(IOptionsMonitor<ConsulOptions> options)
        {
            _options = options.CurrentValue;
        }

        public string? MapAddress(string serviceName, string apiPath)
        {
            if (string.IsNullOrEmpty(serviceName) || string.IsNullOrEmpty(apiPath))
                return null;

            var serviceList = GetServiceList(serviceName);
            if (serviceList == null || serviceList.Length == 0)
                return null;

            var service = ChooseService(serviceList);
            if (service == null) return null;

            if (!apiPath.StartsWith('/')) apiPath = $"/{apiPath}";

            return $"http://{service.Address}:{service.Port}{apiPath}";
        }

        /// <summary>
        /// 获取清单注册服务列表
        /// </summary>
        private ServiceEntry[] GetServiceList(string serviceName)
        {
            using ConsulClient client = GetClient();
            return client.Health.Service(serviceName).Result.Response;
        }

        protected abstract AgentService ChooseService(ServiceEntry[] serviceList);

        private ConsulClient GetClient() => new(c =>
        {
            c.Address = new Uri($"http://{_options.ConsulIP}:{_options.ConsulPort}/");
            c.Datacenter = _options.DataCenter;
        });
    }

    public enum ConsulDispatcherType
    {
        Random = 0,
        Polling = 1,
        Weight = 2
    }

    /// <summary>
    /// 随机
    /// </summary>
    public class ConsulRandomDispatcher : ConsulDispatcher
    {
        public ConsulRandomDispatcher(IOptionsMonitor<ConsulOptions> options) : base(options)
        {
        }

        protected override AgentService ChooseService(ServiceEntry[] serviceList)
        {
            var index = new Random(DateTime.Now.Millisecond).Next(0, int.MaxValue) % serviceList.Length;
            return serviceList[index].Service;
        }
    }

    /// <summary>
    /// 轮询
    /// </summary>
    public class ConsulPollingDispatcher : ConsulDispatcher
    {
        private static int _index = 0;

        private static int Index
        {
            get
            {
                return _index;
            }
            set
            {
                _index = value >= int.MaxValue ? 0 : value;
            }
        }

        public ConsulPollingDispatcher(IOptionsMonitor<ConsulOptions> options) : base(options)
        {
        }

        protected override AgentService ChooseService(ServiceEntry[] serviceList)
        {
            var index = Index++ % serviceList.Length;
            return serviceList[index].Service;
        }
    }

    /// <summary>
    /// 权重
    /// </summary>
    public class ConsulWeightDispatcher : ConsulDispatcher
    {
        public ConsulWeightDispatcher(IOptionsMonitor<ConsulOptions> options) : base(options)
        {
        }

        protected override AgentService ChooseService(ServiceEntry[] serviceList)
        {
            List<AgentService> agentServices = new();
            foreach (var item in serviceList)
            {
                if (!int.TryParse(item.Service.Tags?[0], out int weight))
                {
                    weight = 1;
                }

                agentServices.AddRange(Enumerable.Repeat(item.Service, weight));
            }

            int index = new Random(DateTime.Now.Millisecond).Next(0, int.MaxValue) % agentServices.Count;
            return agentServices[index];
        }
    }
}
